﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using Sunny.UI;

namespace DevelopTool.Common
{
    /// <summary>
    /// DataTable扩展类
    /// </summary>
    public static class DataTableHelper
    {
        /// <summary>
        /// DataTable转josn 并压缩
        /// </summary>
        /// <param name="dataTable"></param>
        /// <param name="withSign">是否包含开头和结尾的[]中括号</param>
        /// <returns></returns>
        public static string DataTableToJson_GZipCompress(this DataTable dataTable)
        {
            if(dataTable == null) return string.Empty;

            return DataTableToJson(dataTable).GZipCompress();
        }


        /// <summary>
        /// json转DataTable，并解压
        /// </summary>
        /// <param name="json"></param>
        /// <param name="withSign">是否包含开头和结尾的[]中括号</param>
        /// <returns></returns>
        public static DataTable JsonToDataTable_GZipDecompress(this string json,bool withSign = true)
        {
            if(string.IsNullOrEmpty(json)) return new DataTable();

            if(withSign)
            {
                string jsonStr = json.GZipDecompress();//先解压字符串为json
                if(jsonStr.IndexOf('[') != 0)
                {
                    jsonStr = "[" + jsonStr;//如果开头没有中括号‘[’则加上
                }

                if(jsonStr.LastIndexOf(']') != jsonStr.Length - 1)
                {
                    jsonStr = jsonStr + "]";//如果结尾没有中括号‘]’则加上
                }

                return JsonToDataTable(jsonStr);
            }
            else
            {

                return JsonToDataTable(json.GZipDecompress());
            }

        }



        /// <summary>
        /// DataTable转为Json
        /// </summary>
        /// <param name="dataTable"></param>
        /// <returns></returns>
        public static string DataTableToJson(this DataTable dataTable)
        {
            return JsonHelper.SerializeObject(dataTable);
        }

        /// <summary>
        /// Json转为DataTable
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public static DataTable JsonToDataTable(this string json)
        {
            return JsonHelper.DeserializeObject<DataTable>(json);
        }



        /// <summary>
        /// datatable转List
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static List<T> ToList<T>(this DataTable dt) where T : class, new()
        {
            var list = new List<T>();
            if(dt == null || dt.Rows.Count == 0)
            {
                return list;
            }

            list.AddRange(dt.Rows.Cast<DataRow>().Select(info => DataTableBuilder<T>.CreateBuilder(dt.Rows[0]).Build(info)));
            return list;
        }

        /// <summary>
        /// 将泛型集合类转换成DataTable
        /// </summary>
        /// <typeparam name="T">集合项类型</typeparam>
        /// <param name="list">集合</param>
        /// <param name="tableName">表名</param>
        /// <returns>数据集(表)</returns>
        public static DataTable ToDataTable<T>(this IEnumerable<T> list,string tableName = null)
        {
            return ToDataTable(list.ToList(),tableName);
        }

        /// <summary>
        /// 将泛型集合类转换成DataTable
        /// </summary>
        /// <typeparam name="T">集合项类型</typeparam>
        /// <param name="list">集合</param>
        /// <param name="tableName">表名</param>
        /// <returns>数据集(表)</returns>
        public static DataTable ToDataTable<T>(this IList<T> list,string tableName = null)
        {
            var result = new DataTable(tableName);
            if(list.Count <= 0)
            {
                return result;
            }

            var properties = list[0].GetType().GetProperties();
            result.Columns.AddRange(properties.Select(p =>
            {
                if(p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    return new DataColumn(p.GetCustomAttribute<DescriptionAttribute>()?.Description ?? p.Name,Nullable.GetUnderlyingType(p.PropertyType));
                }

                return new DataColumn(p.GetCustomAttribute<DescriptionAttribute>()?.Description ?? p.Name,p.PropertyType);
            }).ToArray());
            list.ForEach(item => result.LoadDataRow(properties.Select(p => p.GetValue(item,null)).ToArray(),true));
            return result;
        }


        /// <summary>
        /// 根据nameList里面的字段创建一个表格,返回该表格的DataTable
        /// </summary>
        /// <param name="nameList">包含字段信息的列表</param>
        /// <returns>DataTable</returns>
        public static DataTable CreateTable(this List<string> nameList)
        {
            if(nameList.Count <= 0)
            {
                return null;
            }

            var myDataTable = new DataTable();
            foreach(string columnName in nameList)
            {
                myDataTable.Columns.Add(columnName,typeof(string));
            }

            return myDataTable;
        }

        /// <summary>
        /// 给DataTable增加一个自增列
        /// 如果DataTable 存在 identityid 字段  则 直接返回DataTable 不做任何处理
        /// </summary>
        /// <param name="dt">DataTable</param>
        /// <returns>返回Datatable 增加字段 identityid </returns>
        public static DataTable AddIdentityColumn(this DataTable dt)
        {
            if(!dt.Columns.Contains("identityid"))
            {
                dt.Columns.Add("identityid",typeof(int));
                for(int i = 0 ; i < dt.Rows.Count ; i++)
                {
                    dt.Rows[i]["identityid"] = (i + 1).ToString();
                }
            }

            return dt;
        }

        /// <summary>
        /// DataGridView转DataTable的扩展方法
        /// </summary>
        /// <param name="dgv"></param>
        /// <returns></returns>
        public static DataTable ToDataTable(this DataGridView dgv)
        {
            DataTable dt = new DataTable();
            for(int i = 0 ; i < dgv.ColumnCount ; i++)
            {
                if(dt.Columns.Contains(dgv.Columns[i].HeaderText))
                    dt.Columns.Add(dgv.Columns[i].HeaderText + i,dgv.Columns[i].ValueType);
                else
                    dt.Columns.Add(dgv.Columns[i].HeaderText,dgv.Columns[i].ValueType);
            }
            //写入数值
            for(int r = 0 ; r < dgv.Rows.Count ; r++)
            {
                List<object> values = new List<object>();
                for(int i = 0 ; i < dgv.ColumnCount ; i++)
                {
                    values.Add(dgv.Rows[r].Cells[i].Value);
                }
                dt.Rows.Add(values.ToArray());
            }
            return dt;
        }


        /// <summary>
        /// 获取DataTable中是否包含指定列
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="columnName"></param>
        /// <returns></returns>
        public static bool HasColumn(this DataTable dt,string columnName)
        {
            bool exist = false;
            foreach(DataColumn column in dt.Columns)
            {
                if(column.ColumnName == columnName)
                {
                    exist = true;
                    break;
                }
            }
            return exist;
        }

        /// <summary>
        /// 批量设置DataTable某一列的值
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="columnName"></param>
        /// <param name="value"></param>
        public static void BatchSetValue(this DataTable dt,string columnName,object value)
        {
            for(int i = 0 ; i < dt.Rows.Count ; i++)
            {
                dt.Rows[i][columnName] = value;
            }
        }


        /// <summary>
        /// 批量设置DataTable某一列的值为GUID
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="columnName"></param>
        public static void BatchSetValueWithGuid(this DataTable dt,string columnName)
        {
            for(int i = 0 ; i < dt.Rows.Count ; i++)
            {
                dt.Rows[i][columnName] = Guid.NewGuid().ToString("N");
            }
        }



        /// <summary>
        /// DataTable转成List
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static List<T> ToDataList<T>(this DataTable dt)
        {
            var list = new List<T>();
            var plist = new List<PropertyInfo>(typeof(T).GetProperties());
            foreach(DataRow item in dt.Rows)
            {
                T s = Activator.CreateInstance<T>();
                for(int i = 0 ; i < dt.Columns.Count ; i++)
                {
                    PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName);
                    if(info != null)
                    {
                        try
                        {
                            if(!Convert.IsDBNull(item[i]))
                            {
                                object v = null;
                                if(info.PropertyType.ToString().Contains("System.Nullable"))
                                {
                                    v = Convert.ChangeType(item[i],Nullable.GetUnderlyingType(info.PropertyType));
                                }
                                else
                                {
                                    v = Convert.ChangeType(item[i],info.PropertyType);
                                }
                                info.SetValue(s,v,null);
                            }
                        }
                        catch(Exception ex)
                        {
                            throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message);
                        }
                    }
                }
                list.Add(s);
            }
            return list;
        }

        /// <summary>
        /// DataTable转成Dto
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static T ToDataDto<T>(this DataTable dt)
        {
            T s = Activator.CreateInstance<T>();
            if(dt == null || dt.Rows.Count == 0)
            {
                return s;
            }
            var plist = new List<PropertyInfo>(typeof(T).GetProperties());
            for(int i = 0 ; i < dt.Columns.Count ; i++)
            {
                PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName);
                if(info != null)
                {
                    try
                    {
                        if(!Convert.IsDBNull(dt.Rows[0][i]))
                        {
                            object v = null;
                            if(info.PropertyType.ToString().Contains("System.Nullable"))
                            {
                                v = Convert.ChangeType(dt.Rows[0][i],Nullable.GetUnderlyingType(info.PropertyType));
                            }
                            else
                            {
                                v = Convert.ChangeType(dt.Rows[0][i],info.PropertyType);
                            }
                            info.SetValue(s,v,null);
                        }
                    }
                    catch(Exception ex)
                    {
                        throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message);
                    }
                }
            }
            return s;
        }

        /// <summary>
        /// 将实体集合转换为DataTable
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="entities">实体集合</param>
        public static DataTable ToDataTable<T>(List<T> entities)
        {
            var result = CreateTable<T>();
            FillData(result,entities);
            return result;
        }

        /// <summary>
        /// 创建表
        /// </summary>
        private static DataTable CreateTable<T>()
        {
            var result = new DataTable();
            var type = typeof(T);
            foreach(var property in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
            {
                var propertyType = property.PropertyType;
                if((propertyType.IsGenericType) && (propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                    propertyType = propertyType.GetGenericArguments()[0];
                result.Columns.Add(property.Name,propertyType);
            }
            return result;
        }

        /// <summary>
        /// 填充数据
        /// </summary>
        private static void FillData<T>(DataTable dt,IEnumerable<T> entities)
        {
            foreach(var entity in entities)
            {
                dt.Rows.Add(CreateRow(dt,entity));
            }
        }

        /// <summary>
        /// 创建行
        /// </summary>
        private static DataRow CreateRow<T>(DataTable dt,T entity)
        {
            DataRow row = dt.NewRow();
            var type = typeof(T);
            foreach(var property in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
            {
                row[property.Name] = property.GetValue(entity,null) ?? DBNull.Value;
            }
            return row;
        }
    }
}
